package com.msf.tutorial.java8.chapter10;

import com.msf.tutorial.java8.Apple;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 分组函数
 */
public class C04Group {

    /**
     * 分组
     */
    public static void group() {
        List<Apple> list = Arrays.asList(
                new Apple(1L, "red", 10D),
                new Apple(2L, "red", 20D),
                new Apple(3L, "green", 50D),
                new Apple(4L, "green", 80D)
        );
        // 按颜色分组
        Map<String, List<Apple>> map1 = list.stream().collect(Collectors.groupingBy(Apple::getColor));

        // 按重量分组,50以下为轻，50-70为正常，80为重
        Map<String, List<Apple>> map2 = list.stream().collect(Collectors.groupingBy(o -> {
            if (o.getWeight() <= 50) return "light";
            if (o.getWeight() > 50 && o.getWeight() <= 70) return "common";
            return "weight";
        }));

    }

    /**
     * 多级分组
     */
    public static void group2() {
        List<Apple> list = Arrays.asList(
                new Apple(1L, "red", 10D),
                new Apple(2L, "red", 20D),
                new Apple(3L, "green", 50D),
                new Apple(4L, "green", 80D)
        );

        // 先按颜色分组，然后再按重量分组
        Map<String, Map<String, List<Apple>>> map1 = list.stream().collect(Collectors.groupingBy(Apple::getColor, Collectors.groupingBy(o -> {
            if (o.getWeight() <= 50) return "light";
            if (o.getWeight() > 50 && o.getWeight() <= 70) return "common";
            return "weight";
        })));

        // 查找每种颜色中的苹果个数
        Map<String, Long> map2 = list.stream()
                .collect(Collectors.groupingBy(Apple::getColor, Collectors.counting()));

        // 查找每种颜色中最重的苹果
        Map<String, Optional<Apple>> map3 = list.stream()
                .collect(Collectors.groupingBy(Apple::getColor, Collectors.maxBy(Comparator.comparingDouble(Apple::getWeight))));

        // 把收集器的结果转换为另一种类型
        // collectingAndThen：这个方法接受两个参数——要转换的收集器以及转换函数，并返回另一个收集器
        // 查找每种颜色中最重的苹果
        Map<String, Apple> map4 = list.stream()
                .collect(Collectors.groupingBy(Apple::getColor,
                        Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparing(Apple::getWeight)), Optional::get)));

        // groupingBy 联合 summing 收集器
        // 查找每种颜色中的重量总和
        Map<String, Double> map5 = list.stream()
                .collect(Collectors.groupingBy(Apple::getColor, Collectors.summingDouble(Apple::getWeight)));

        // groupingBy 联合 mapping 收集器
        // 这个方法接受两个参数：一个函数对流中的元素做变换，另一个则将变换的结果对象收集起来
        // 其目的是在累加之前对每个输入元素应用一个映射函数，这样就可以让接受特定类型元素的收集器适应不同类型的对象
        // 查找每种颜色中有哪几种重量级别
        Map<String, Set<String>> map6 = list.stream()
                .collect(Collectors.groupingBy(Apple::getColor, Collectors.mapping(o -> {
                    if (o.getWeight() <= 50) return "light";
                    if (o.getWeight() > 50 && o.getWeight() <= 70) return "common";
                    return "weight";
                }, Collectors.toSet())));


        // 生成指定类型的Set
        Map<String, HashSet<String>> map7 = list.stream()
                .collect(Collectors.groupingBy(Apple::getColor, Collectors.mapping(o -> {
                    if (o.getWeight() <= 50) return "light";
                    if (o.getWeight() > 50 && o.getWeight() <= 70) return "common";
                    return "weight";
                }, Collectors.toCollection(HashSet::new))));
    }

}
